package stone926.mods.more_enchantments.util;

import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtList;
import net.minecraft.util.registry.Registry;
import org.apache.commons.lang3.tuple.Triple;
import stone926.mods.more_enchantments.enchantments.EffectEnchantment;
import stone926.mods.more_enchantments.enchantments.cleanUp.AbstractCleanUpEnchantment;
import stone926.mods.more_enchantments.enchantments.creative.AbstractCreativeOnlyEnchantment;
import stone926.mods.more_enchantments.enchantments.damage.AbstractStoneDamageEnchantment;
import stone926.mods.more_enchantments.enchantments.legendary.AbstractLegendaryEnchantment;
import stone926.mods.more_enchantments.enchantments.negative.AbstractNegativeEnchantment;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.BiConsumer;

public final class EnchantmentUtil {

  public static final List<AbstractStoneDamageEnchantment> STONE_DAMAGE_ENCHANTMENTS = new ArrayList<>();
  public static final List<AbstractCreativeOnlyEnchantment> CREATIVE_ONLY_ENCHANTMENTS = new ArrayList<>();
  public static final List<AbstractCleanUpEnchantment> CLEAN_UP_ENCHANTMENTS = new ArrayList<>();
  public static final List<AbstractNegativeEnchantment> NEGATIVE_ENCHANTMENTS = new ArrayList<>();
  public static final List<AbstractLegendaryEnchantment> LEGENDARY_ENCHANTMENTS = new ArrayList<>();
  public static final List<EffectEnchantment> EFFECT_ENCHANTMENTS = new ArrayList<>();
  public static final EquipmentSlot[] ALL_ARMOR = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
  public static final EquipmentSlot[] ALL_SLOT = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET, EquipmentSlot.OFFHAND, EquipmentSlot.MAINHAND};
  public static final EquipmentSlot[] ALL_HAND = new EquipmentSlot[]{EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND};

  public static List<AbstractStoneDamageEnchantment> getStoneDamageEnchantments() {
    return STONE_DAMAGE_ENCHANTMENTS;
  }

  public static List<AbstractCreativeOnlyEnchantment> getCreativeOnlyEnchantmentList() {
    return CREATIVE_ONLY_ENCHANTMENTS;
  }

  public static boolean hasEnchantment(Enchantment enchantment, ItemStack stack) {
    return EnchantmentHelper.getLevel(enchantment, stack) > 0;
  }

  public static boolean hasEquipmentEnchantment(Enchantment enchantment, LivingEntity entity) {
    return EnchantmentHelper.getEquipmentLevel(enchantment, entity) > 0;
  }

  public static int getTotalEquipmentLvl(Enchantment enchantment, LivingEntity livingEntity) {
    int i = 0;
    for (ItemStack itemStack : enchantment.getEquipment(livingEntity).values()) {
      int j = EnchantmentHelper.getLevel(enchantment, itemStack);
      i += j;
    }
    return i;
  }

  /**
   * 遍历stack中的每一个附魔
   *
   * @param consumer 第一个参数是stack中的一个附魔，第二个是该附魔的等级
   * @param stack    要遍历附魔的物品组
   */
  public static void forEachEnchantment(BiConsumer<Enchantment, Integer> consumer, ItemStack stack) {
    if (!stack.isEmpty()) {
      NbtList nbtList = stack.getEnchantments();
      for (int i = 0; i < nbtList.size(); ++i) {
        NbtCompound nbtCompound = nbtList.getCompound(i);
        Registry.ENCHANTMENT.getOrEmpty(EnchantmentHelper.getIdFromNbt(nbtCompound)).ifPresent((enchantment) -> {
          consumer.accept(enchantment, EnchantmentHelper.getLevelFromNbt(nbtCompound));
        });
      }
    }
  }

  /**
   * 遍历stack中的每一个附魔
   *
   * @param consumer 第一个参数是stack中的一个附魔，第二个是该附魔的等级
   * @param stacks   要遍历附魔的物品组列表
   */
  public static void forEachEnchantment(BiConsumer<Enchantment, Integer> consumer, Iterable<ItemStack> stacks) {
    for (ItemStack itemStack : stacks) {forEachEnchantment(consumer, itemStack);}
  }

  public static ItemStack enchant(ItemStack stack, Enchantment enchantment, int lvl) {
    stack.addEnchantment(enchantment, lvl);
    return stack;
  }

  /**
   * 给stack按一定几率附魔上ench中的附魔
   *
   * @param stack  要附魔的物品
   * @param ench   一组附魔
   * @param chance 附魔几率
   * @param random 随机
   * @return 传入的stack
   */
  public static ItemStack enchant(ItemStack stack, Map<Enchantment, Triple<Integer, Integer, Double>> ench, double chance, Random random) {
    ench.forEach(((enchantment, triple) -> {
      if (RandomUtil.isPossible(chance, random) && RandomUtil.isPossible(triple.getRight(), random)) {
        stack.addEnchantment(enchantment, RandomUtil.nextInt(triple.getLeft(), triple.getMiddle(), random));
      }
    }));
    return stack;
  }

  public static ItemStack enchant(ItemStack stack1, Map<Enchantment, Triple<Integer, Integer, Double>> ench, Random random) {
    return enchant(stack1, ench, 1, random);
  }

}
